Other UI Optimization Techniques and Tips

译文

Other UI Optimization Techniques and Tips
其他UI的优化技巧和提示

版本检查: 2017.3
难度: 高级

Sometimes there is just no clean way to optimize a UI. This section contains a handful of suggestions that may help improve UI performance, but some are “unclean” structurally, may be difficult to maintain, or may have ugly side effects. Others may be workarounds for behavior in the UI intended to simplify initial development, but also make it relatively simple to create performance problems.
有时候,没有简洁的方法来优化UI。本节包含一些可能有助于提高UI性能的建议,但有些建议在结构上“不干净”,可能难以维护,或者可能具有糟糕的副作用。其他的可能是简化初始开发的UI中的行为的方法,但也使创建性能问题变得相对简单。

RectTransform-based Layouts
基于RectTransform的布局

Layout components are relatively expensive, as they must recompute the sizes and positions of their child elements each time they are marked dirty. (See the Graphic rebuild section of the Fundamentals chapter for details.) If there is a relatively small and fixed number of elements within a given Layout, and the Layout has a relatively simple structure, it may be possible to replace the Layout with a RectTransform-based layout.
布局组件相对来说比较昂贵,因为它们必须在每次标记为dirty时重新计算它们的子元素的大小和位置。(详情请参阅Fundamentals章节的Graphic rebuild部分。)如果给定布局中有相对较小且固定数量的元素,并且布局有一个相对简单的结构,那么可以使用RectTransform的布局来替换布局。

By assigning the anchors of a RectTransform, the RectTransform’s position and size can be made to scale based on its parent. For example, a simple two-column layout can be achieved with two RectTransforms:
通过分配RectTransform的锚点,RectTransform的位置和大小可以根据其父级进行缩放。例如,使用两个RectTransforms可以实现简单的两列布局:

      ●  The left column’s anchors should be X: (0, 0.5) and Y: (0, 1)
          左列的锚点应为X:(0,0.5)和Y:(0,1)

      ●  The right column’s anchors should be X: (0.5, 1) and Y: (0, 1)
          右列的锚点应为X:(0.5,1)和Y:(0,1)

The computations of the size and position of the RectTransform will be driven in native code by the Transform system itself. This is generally more performant than relying on the Layout system. It is also possible to write MonoBehaviours that set up a RectTransform-based Layout. However, this is a relatively complex task and lies beyond the scope of this guide.
RectTransform的大小和位置的计算将由Transform系统本身在本机代码中驱动。这通常比依赖布局系统更高效。也可以编写MonoBehaviours来设置基于RectTransform的布局。但是,这是一项相对复杂的任务,超出了本指南的范围。

Disabling Canvases
禁用画布

When showing or hiding discrete portions of a UI, it is common to enable or disable the GameObject at the root of the UI. This ensures that no component in the disabled UI receives input or Unity callbacks.
在显示或隐藏UI的离散部分时,通常在UI的根部启用或禁用GameObject。这确保了禁用UI中的任何组件都不会接收输入或Unity回调。

However, this also causes the Canvas to discard its VBO data. Re-enabling the Canvas will require the Canvas (and any Sub-canvases) to run the rebuild and rebatch processes. If this happens frequently, the increased CPU usage can cause the application’s frame rate to stutter.
但是,这也会导致Canvas丢弃了VBO数据。重新启用Canvas将需要Canvas(以及任何Sub-canvases)来运行重建和重新分配过程。如果经常发生这种情况,CPU使用率的增加可能会导致应用程序的帧速率降低。

One possible, but hacky, workaround is to place the UI to be shown/hidden onto its own Canvas or Sub-canvas and then to merely enable/disable the Canvas component on this object.
一种可能但又很糟糕的解决方法是将UI显示/隐藏到其自己的Canvas或Sub-canvas上,然后仅启用/禁用此对象上的Canvas组件。

This will cause the UI’s meshes to not be drawn, but they will remain resident in memory and their original batching will be preserved. Further, no OnEnable or OnDisable callbacks will be invoked in the UI’s hierarchy.
这将导致UI的网格不被绘制,但是它们将保留在内存中,并且它们的原始批处理将被保留。此外,在UI的层次结构中不会调用OnEnableOnDisable回调。

Note, however, that this will not disable any MonoBehaviours within the hidden UI, and so these MonoBehaviours will still receive Unity lifecycle callbacks, such as Update.
但请注意,这不会禁用隐藏UI中的任何MonoBehaviours,因此这些MonoBehaviours仍将接收Unity生命周期回调,例如Update。

To avoid this issue, MonoBehaviours on UIs that will be disabled in this manner should not directly implement Unity’s lifecycle callbacks, but should instead receive their callbacks from a “Callback Manager” MonoBehaviour on the UI’s root GameObject. This “Callback Manager” can be informed whenever the UI is shown/hidden, and can ensure that lifecycle events are propagated or not propagated as necessary. Further explanation of this “Callback Manager” pattern is beyond the scope of this guide.
为了避免这个问题,将以这种方式禁用的UI上的MonoBehaviours不应该直接实现Unity的生命周期回调,而应该从UI的根GameObject上的“回调管理器”MonoBehaviour接收回调。无论何时显示/隐藏UI,都可以通知此“回调管理器”,并且可以确保生命周期事件在必要时传播或不传播。有关此“回调管理器”模式的进一步说明超出了本指南的范围。

Assigning Event Cameras
分配事件相机

If using Unity’s built-in Input Managers alongside Canvases set to render in the World Space or Screen Space – Camera modes, it is important to always set the Event Camera or Render Camera property, respectively. From script, this is always exposed as the worldCamera property.
如果将Unity的内置输入管理器与Canvases一起设置为在World Space或Screen Space - Camera模式下渲染,则始终分别设置Event Camera或Render Camera属性非常重要。从脚本开始,它始终显示为worldCamera属性。

If this property is not set, then Unity UI will search for the main camera by looking for Camera components attached to GameObjects with the Main Camera tag. This lookup will occur at least once per World Space or Camera Space Canvas. As GameObject.FindWithTag is known to be slow, it is strongly recommended that all World Space and Camera Space Canvases have their Camera properties assigned at design-time or initialization time.
如果没有设置此属性,则Unity UI将通过查找使用Main Camera标记附加到GameObjects的Camera组件来搜索主摄像机。每个World Space或Camera Space Canvas至少会发生一次此查找。由于已知GameObject.FindWithTag较慢,因此强烈建议所有World Space和Camera Space画布在设计时或初始化时分配其Camera属性。

This issue does not occur for Overlay Canvases.
Overlay Canvases不会出现此问题。

UI Source Code Customization
UI源代码自定义

The UI system has been designed to support a large number of use cases. This flexibility is great, but it also means that some optimizations can’t easily be done without breaking other features. If you end up in a situation where you could gain some CPU cycles by changing the C# UI source code, it is possible to recompile the UI DLL and overwrite the one shipped with Unity. This procedure is documented in the readme file in the Bitbucket repository. Make sure to get the source code corresponding to your Unity version.
UI系统被设计用来支持大量的用例。这种灵活性很好,但也意味着一些优化在不破坏其他特性的情况下是不容易完成的。如果你在这样的情况下,通过更改C#UI源代码可以获得一些CPU周期,那么就可以重新编译UI DLL,并覆盖Unity附带的DLL。此过程记录在Bitbucket存储库的自述文件中。确保获得与Unity版本对应的源代码。

The UI system has been designed to support a large number of use cases. This flexibility is great, but it also means that some optimizations can’t easily be done without breaking other features. If you end up in a situation where you could gain some CPU cycles by changing the C# UI source code, it is possible to recompile the UI DLL and overwrite the one shipped with Unity. This procedure is documented in the readme file in the Bitbucket repository. Make sure to get the source code corresponding to your Unity version.
这应该只是作为最后的手段,因为有一些重要的缺点。首先,你必须找到一种方法将这个新DLL分发给开发人员和构建计算机。然后,每次升级Unity时,都必须将更改与新的UI源代码合并。确保在进入该方向之前,不能只扩展现有类或编写自己的组件版本。


相关链接

  1. 原文地址: https://unity3d.com/cn/learn/tutorials/topics/best-practices/other-ui-optimization-techniques-and-tips